
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <signal.h>

#include "../include/Iec104CommHandler.h"
#include "CLogger.h"
#include "global_data_struct.h"

#include "../../pemd/include/app.h"
#include "../../common/include/common.h"

CIec104CommHandler  CIec104CommHandler::c_iec104CommHandler;

#define  MAX_PAYLOAD_SIZE  220

CS104_Slave      glslave;   //正向104
CS104_Connection glconn;    //反向104

bool    glrun = false;
bool    glreverse104 = false;
typedef  struct _iec104CommPtr_
{
    CIec104CommHandler*  pcomm_ptr;
    CS101_ASDU asdu;
}st_iec104_commptr;


void sigusr_handler(int signalId)
{
    CLogger::getInstance()->log_d("sigusr_handler recved interrupt signal=%d", signalId);

    glrun = false;

    if (glreverse104) {
        CS104_Connection_destroy(glconn);
    }
    else{
        CS104_Slave_stop(glslave);
        CS104_Slave_destroy(glslave);
    }
}

CIec104CommHandler::CIec104CommHandler()
{
    c_connActived = false;
}


CIec104CommHandler::~CIec104CommHandler()
{
    client_stop();
}

CIec104CommHandler* CIec104CommHandler::getInstance()
{
    return &c_iec104CommHandler;
}

void CIec104CommHandler::init(std::shared_ptr<CConfigManager> cm, std::shared_ptr<DataCenterManager> dcm,
    std::shared_ptr<CMosquittoManager> mm, std::shared_ptr<TaskManager> tm, bool reverse)
{
    c_cm = cm;
    c_dcm = dcm;
    c_mm = mm;
    c_tm = tm;
    glreverse104 = reverse;
    if (reverse)
    {
        //主站地址和端口
        auto iec104_rule = cm->get_iec104_rules();
        auto it104 = iec104_rule->begin();
        if (it104 != iec104_rule->end())
        {
            c_master_addr = it104->second.master_addr;
            c_master_port = it104->second.master_port;
            strncpy(c_register_code, it104->second.regsiter_code.c_str(), sizeof(c_register_code) -1);
        }
    }

    c_iec104ServiceManager.init(cm, dcm);
}

int CIec104CommHandler::client_init()
{
    if (glreverse104)
    {
        return reverse_client_init();
    }
    else{
        return normal_client_init();
    }
}

int  CIec104CommHandler::normal_client_init()
{
    signal(SIGUSR1, sigusr_handler);

    glrun = true;
    pthread_create(&c_thrdid_servermode_conn, NULL, servermode_comm_thread, this);

    return 0;
}

void* CIec104CommHandler::servermode_comm_thread(void *arg)
{
    if (!arg){
        return nullptr;
    }
    pthread_detach(pthread_self());

    CIec104CommHandler *commHandler = (CIec104CommHandler *)arg;

    commHandler->c_slave = CS104_Slave_create(10, 10);

    CS104_Slave_setLocalAddress(commHandler->c_slave, "0.0.0.0");

    // Set mode to a single redundancy group
    CS104_Slave_setServerMode(commHandler->c_slave, CS104_MODE_SINGLE_REDUNDANCY_GROUP);

    // get the connection parameters
    commHandler->c_alParams = CS104_Slave_getAppLayerParameters(commHandler->c_slave);

    CS104_APCIParameters apciParams = CS104_Slave_getConnectionParameters(commHandler->c_slave);

    /* set the callback handler for the clock synchronization command */
    CS104_Slave_setClockSyncHandler(commHandler->c_slave, commHandler->clockSyncHandler, NULL);

    /* set handler for other message types */
    CS104_Slave_setASDUHandler(commHandler->c_slave, commHandler->asduHandler, commHandler);

    /* set handler to handle connection requests (optional) */
    CS104_Slave_setConnectionRequestHandler(commHandler->c_slave, commHandler->connectionRequestHandler, NULL);

    /* set handler to track connection events (optional) */
    CS104_Slave_setConnectionEventHandler(commHandler->c_slave, commHandler->connectionEventHandler, commHandler);

    /* set the callback handler for the interrogation command */
    CS104_Slave_setInterrogationHandler(commHandler->c_slave, commHandler->interrogationHandler, commHandler);

    CS104_Slave_start(commHandler->c_slave);

    if (CS104_Slave_isRunning(commHandler->c_slave) == false) {
        CLogger::getInstance()->LOG_E("Starting  IEC104 client failed!");
        return nullptr;
    }

    glslave = commHandler->c_slave;
    CLogger::getInstance()->LOG_I("Starting  IEC104 client success!");

    while (glrun)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    return nullptr;
}

int  CIec104CommHandler::reverse_client_init()
{
    if ((0 == c_master_port) || ("" == c_master_addr))
    {
        CLogger::getInstance()->LOG_W("reverse client init error,port or address invalid!");
        return -1;
    }

    glrun = true;
    signal(SIGUSR1, sigusr_handler);

    //strncpy(c_register_code, reg_code, sizeof(c_register_code));

    c_lastrecv_time = get_timestamp();
    c_curr_time = get_timestamp();

    pthread_create(&c_thread_id_conn, NULL, comm_thread, this);
    pthread_create(&c_thread_id_monitor, NULL, monitor_thread, this);

    return 0;
}

void  CIec104CommHandler::create_send_singlePoint_Asdu(int ca, int ti, int cot, std::list<ST_IEC104_PTVAL> lstObjs, IMasterConnection connection, bool bInterr)
{
    CS101_ASDU newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);

    int count = 0;
    auto iti = lstObjs.begin();
    while (iti != lstObjs.end())
    {
        if (ti == M_SP_NA_1)   //单点信息
        {
            InformationObject io = (InformationObject)SinglePointInformation_create(NULL, iti->ioa, (bool)iti->val, IEC60870_QUALITY_GOOD);
            CS101_ASDU_addInformationObject(newAsdu, io);
            InformationObject_destroy(io);
        }
        else if (ti == M_SP_TB_1)//带CP56Time2a时标的单点信息
        {
            InformationObject io = (InformationObject)SinglePointWithCP56Time2a_create(NULL, iti->ioa, (bool)iti->val, IEC60870_QUALITY_GOOD, iti->acq_time);
            CS101_ASDU_addInformationObject(newAsdu, io);
            InformationObject_destroy(io);
        }
        else{
            CLogger::getInstance()->LOG_I("create_send_singlePoint_Asdu,the ti=%d not support.", ti);
            continue;
        }
        count++;
        int payload_size = CS101_ASDU_getPayloadSize(newAsdu);
        if (payload_size >= MAX_PAYLOAD_SIZE)
        {
            if (glreverse104){
                CS104_Connection_sendASDU(glconn, newAsdu);
            }
            else{
                if (bInterr){
                    IMasterConnection_sendASDU(connection, newAsdu);
                }
                else{
                    CS104_Slave_enqueueASDU(c_slave, newAsdu);
                }
            }
            CS101_ASDU_destroy(newAsdu);
            CLogger::getInstance()->log_i("单点遥信ASDU已发送,point num=%d", count);

            count = 0;
            iti++;
            newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);
            continue;
        }
        iti++;
    }
    if (count > 0)
    {
        if (glreverse104){
            CS104_Connection_sendASDU(glconn, newAsdu);
        }
        else{
            if (bInterr){
                IMasterConnection_sendASDU(connection, newAsdu);
            }
            else{
                CS104_Slave_enqueueASDU(c_slave, newAsdu);
            }
        }
        CLogger::getInstance()->log_i("单点遥信ASDU已发送,point num=%d", count);
    }
    CS101_ASDU_destroy(newAsdu);

    CLogger::getInstance()->log_d("create_send_singlePoint_Asdu end.");

}

void CIec104CommHandler::create_send_doublePoint_Asdu(int ca, int ti, int cot, std::list<ST_IEC104_PTVAL> lstObjs, IMasterConnection connection, bool bInterr)
{
    CS101_ASDU newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);

    int count = 0;
    auto iti = lstObjs.begin();
    while (iti != lstObjs.end())
    {
        if (ti == M_DP_TA_1)    //不带时标的双点信息
        {
            InformationObject io = (InformationObject)DoublePointInformation_create(NULL, iti->ioa, (DoublePointValue)iti->val, IEC60870_QUALITY_GOOD);
            CS101_ASDU_addInformationObject(newAsdu, io);
            InformationObject_destroy(io);
        }
        else if (ti == M_DP_TB_1) //带CP56Time2a时标的双点信息
        {
            InformationObject io = (InformationObject)DoublePointWithCP56Time2a_create(NULL, iti->ioa, (DoublePointValue)iti->val, IEC60870_QUALITY_GOOD, iti->acq_time);
            CS101_ASDU_addInformationObject(newAsdu, io);
            InformationObject_destroy(io);
        }
        else {
            CLogger::getInstance()->log_d("create_send_doublePoint_Asdu,the ti=%d not support.", ti);
            continue;
        }

        count++;
        int payload_size = CS101_ASDU_getPayloadSize(newAsdu);
        if (payload_size >= MAX_PAYLOAD_SIZE)
        {
            if (glreverse104){
                CS104_Connection_sendASDU(glconn, newAsdu);
            }
            else{
                if (bInterr){
                    IMasterConnection_sendASDU(connection, newAsdu);
                }
                else{
                    CS104_Slave_enqueueASDU(c_slave, newAsdu);
                }
            }
            CS101_ASDU_destroy(newAsdu);
            CLogger::getInstance()->log_i("双点遥信ASDU已发送,point num=%d", count);

            count = 0;
            iti++;
            newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);
            continue;
        }
        iti++;
    }
    if (count > 0)
    {
        if (glreverse104){
            CS104_Connection_sendASDU(glconn, newAsdu);
        }
        else{
            if (bInterr){
                IMasterConnection_sendASDU(connection, newAsdu);
            }
            else{
                CS104_Slave_enqueueASDU(c_slave, newAsdu);
            }
        }
        CLogger::getInstance()->log_i("双点遥信ASDU已发送,point num=%d", count);
    }
    CS101_ASDU_destroy(newAsdu);

}

void CIec104CommHandler::create_send_MeasuredPoint_Asdu(int ca, int ti, int cot, std::list<ST_IEC104_MEAR_VAL> lstMearObjs, IMasterConnection connection, bool bInterr)
{
    //创建遥测ASDU
    CS101_ASDU newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);

    int count = 0;
    auto ito = lstMearObjs.begin();
    while (ito != lstMearObjs.end())
    {
        append_measureinfobj_toasdu(ti, newAsdu, ito->ioa, ito->fval, ito->acq_time);

        int payload_size = CS101_ASDU_getPayloadSize(newAsdu);
        if (payload_size >= MAX_PAYLOAD_SIZE)
        {
            if (glreverse104){
                CS104_Connection_sendASDU(glconn, newAsdu);
            }
            else{
                if (bInterr){
                    IMasterConnection_sendASDU(connection, newAsdu);
                }
                else{
                    CS104_Slave_enqueueASDU(c_slave, newAsdu);
                }
            }
            CS101_ASDU_destroy(newAsdu);
            CLogger::getInstance()->log_i("遥测ASDU已发送,point num=%d", count);

            count = 0;
            ito++;
            newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);
            continue;
        }
        count++;
        ito++;
    }
    if (count > 0)
    {
        if (glreverse104){
            CS104_Connection_sendASDU(glconn, newAsdu);
        }
        else{
            if (bInterr){
                IMasterConnection_sendASDU(connection, newAsdu);
            }
            else{
                CS104_Slave_enqueueASDU(c_slave, newAsdu);
            }
        }
        CLogger::getInstance()->log_i("遥测ASDU已发送,point num=%d", count);
    }
    CS101_ASDU_destroy(newAsdu);
}

void CIec104CommHandler::append_measureinfobj_toasdu(int ti, CS101_ASDU Asdu, int ioa, float fval, CP56Time2a acq_time)
{
    switch (ti)
    {
    case M_ME_NA_1:     //归一化值
    {
        InformationObject  io = (InformationObject)MeasuredValueNormalized_create(NULL, ioa, fval, IEC60870_QUALITY_GOOD);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    case M_ME_TD_1:     //带CP56Time2a时标的归一化值
    {
        InformationObject  io = (InformationObject)MeasuredValueNormalizedWithCP56Time2a_create(NULL, ioa, fval, IEC60870_QUALITY_GOOD, acq_time);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    case M_ME_NB_1:     //标度值
    {
        int scaledValue = (int)fval;
        InformationObject io = (InformationObject)MeasuredValueScaled_create(NULL, ioa, scaledValue, IEC60870_QUALITY_GOOD);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    case M_ME_TE_1:     //带CP56Time2a时标的标度值
    {
        int scaledValue = (int)fval;
        InformationObject io = (InformationObject)MeasuredValueScaledWithCP56Time2a_create(NULL, ioa, scaledValue, IEC60870_QUALITY_GOOD, acq_time);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    case M_ME_NC_1:     //短浮点数
    {
        InformationObject io = (InformationObject)MeasuredValueShort_create(NULL, ioa, fval, IEC60870_QUALITY_GOOD);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    case M_ME_TF_1:  //带CP56TimeE2A时标的短浮点数
    {
        InformationObject io = (InformationObject)MeasuredValueShortWithCP56Time2a_create(NULL, ioa, fval, IEC60870_QUALITY_GOOD, acq_time);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    break;
    default:{
        CLogger::getInstance()->LOG_I("apppend_measureinfobj_toasdu:infomationObj ti=%d not suported.", ti);
    }
    }

}

void CIec104CommHandler::append_intertotalobj_toasdu(int ti, CS101_ASDU Asdu, ST_IEC104_INTERTOTAL_VAL stInterval)
{
    if (M_IT_NA_1 == ti)
    {
        InformationObject io = (InformationObject)IntegratedTotals_create(NULL, stInterval.ioa, stInterval.totalval);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    else if (M_IT_TB_1 == ti)
    {
        InformationObject io = (InformationObject)IntegratedTotalsWithCP56Time2a_create(NULL, stInterval.ioa, stInterval.totalval, stInterval.acq_time);
        CS101_ASDU_addInformationObject(Asdu, io);
        InformationObject_destroy(io);
    }
    else{
        CLogger::getInstance()->log_d("append_intertotalobj_toasdu asdu ti=%d not support", ti);
    }
}

int  CIec104CommHandler::LocalSpontReport(std::string& dev, std::list<ST_CHANGE_REPORT_DATAPT>& lstChangeReportPts)
{
    CLogger::getInstance()->log_d("LocalSpontReport :dev=%s,datasize=%d", dev.c_str(), lstChangeReportPts.size());
    if (!c_connActived)
    {
        CLogger::getInstance()->log_d("LocalSpontReport:the connection is not actived, non-reporting. ");
        return -1;
    }

    int ca = 0;
    ST_APDU_POINT_DATA stApduPonitData;
    ST_APDU_MEASUREDVAL_DATA stApduMearData;
    ST_APDU_INTERRTOTAL_DATA stApduIntertotalData;

    int ret = c_iec104ServiceManager.get_report_data(dev, lstChangeReportPts, ca, stApduPonitData, stApduMearData,stApduIntertotalData);
    if (ret > 0)
    {
        //遥信
        if (stApduPonitData.lstObjs.size() > 0)
        {            
            if ((stApduPonitData.ti == M_SP_NA_1) || (stApduPonitData.ti == M_SP_TB_1))
            {
                create_send_singlePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_SPONTANEOUS, stApduPonitData.lstObjs, nullptr, false);
            }
            else if ((stApduPonitData.ti == M_DP_TA_1) || (stApduPonitData.ti == M_DP_TB_1))
            {
                create_send_doublePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_SPONTANEOUS, stApduPonitData.lstObjs, nullptr, false);
            }
            else{
                CLogger::getInstance()->log_d("LocalSpontReport:ti=%d not support.", stApduPonitData.ti);
            }
        }

        //遥测
        if (stApduMearData.lstObjs.size() > 0)
        {            
            create_send_MeasuredPoint_Asdu(ca, stApduMearData.ti, CS101_COT_SPONTANEOUS, stApduMearData.lstObjs, nullptr, false);
        }

        //遥脉
        if (stApduIntertotalData.lstObjs.size() > 0)
        {
            create_send_CounterInterr_Asdu(ca, stApduIntertotalData.ti, CS101_COT_SPONTANEOUS, stApduIntertotalData.lstObjs, nullptr, false);
        }
    }

    return 0;
}
//响应主站召唤
bool  CIec104CommHandler::interrogationHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu, uint8_t qoi)
{
    if (!parameter) {
        return false;
    }
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)parameter;

    CLogger::getInstance()->log_d("Received interrogation for group %i", qoi);

    if (qoi == 20) { /* 只处理总召唤 */

        CS101_AppLayerParameters alParams = IMasterConnection_getApplicationLayerParameters(connection);
        IMasterConnection_sendACT_CON(connection, asdu, false);
        CLogger::getInstance()->log_d("interrogationHandler ACT sended.");

        int ca = 0;
        ST_APDU_POINT_DATA stApduPonitData;
        ST_APDU_MEASUREDVAL_DATA stApduMearData;
        ST_APDU_INTERRTOTAL_DATA stApduIntertotalData;

        int ret = iec104Comm->c_iec104ServiceManager.get_dc_realtime_data(ca, stApduPonitData, stApduMearData,stApduIntertotalData);
        if (ret > 0)
        {
            //遥信
            if (stApduPonitData.lstObjs.size() > 0)
            {
                if ((stApduPonitData.ti == M_SP_NA_1) || (stApduPonitData.ti == M_SP_TB_1))
                {
                    iec104Comm->create_send_singlePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduPonitData.lstObjs, connection);

                }
                else if ((stApduPonitData.ti == M_DP_TA_1) || (stApduPonitData.ti == M_DP_TB_1))
                {
                    iec104Comm->create_send_doublePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduPonitData.lstObjs, connection);
                }
                else{
                    CLogger::getInstance()->LOG_W("ti=%d not support.", stApduPonitData.ti);
                }
            }

            //遥测
            if (stApduMearData.lstObjs.size() > 0)
            {
                iec104Comm->create_send_MeasuredPoint_Asdu(ca, stApduMearData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduMearData.lstObjs, connection);

            }

            //遥脉
            if (stApduIntertotalData.lstObjs.size() >0)
            {
                iec104Comm->create_send_CounterInterr_Asdu(ca, stApduIntertotalData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduIntertotalData.lstObjs, connection);
            }
            IMasterConnection_sendACT_TERM(connection, asdu);
            CLogger::getInstance()->log_d("interrogation rsp end.");
        }

    }
    else{
        IMasterConnection_sendACT_CON(connection, asdu, true);
        CLogger::getInstance()->log_i("the interrogation not support.");
    }

    return true;
}

bool CIec104CommHandler::asduHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu)
{
    CLogger::getInstance()->log_d("asduHandler received down cmd.");
    if (!parameter) {
        return false;
    }
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)parameter;

    if (CS101_ASDU_getTypeID(asdu) == C_SC_NA_1) { /*单命令*/
        CLogger::getInstance()->log_d("received single command");

        if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION) {  //激活

            iec104Comm->remote_cmd_handler(asdu);
        }
        else
            CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);

        IMasterConnection_sendASDU(connection, asdu);

        return true;
    }

    return false;
}

bool CIec104CommHandler::clockSyncHandler(void* parameter, IMasterConnection connection, CS101_ASDU asdu, CP56Time2a newTime)
{
    char buf[64] = { 0 };
    sprintf(buf, "%02i:%02i:%02i %02i/%02i/%04i", CP56Time2a_getHour(newTime),
        CP56Time2a_getMinute(newTime),
        CP56Time2a_getSecond(newTime),
        CP56Time2a_getDayOfMonth(newTime),
        CP56Time2a_getMonth(newTime),
        CP56Time2a_getYear(newTime) + 2000);


    CLogger::getInstance()->log_d("Process time sync command with time:%s", buf);

    uint64_t newSystemTimeInMs = CP56Time2a_toMsTimestamp(newTime);

    /* Set time for ACT_CON message */
    //CP56Time2a_setFromMsTimestamp(newTime, Hal_getTimeInMs());

    /* update system time here */
}

bool CIec104CommHandler::connectionRequestHandler(void* parameter, const char* ipAddress)
{
    CLogger::getInstance()->log_d("New connection request from %s", ipAddress);

    return true;
}

void CIec104CommHandler::connectionEventHandler(void* parameter, IMasterConnection con, CS104_PeerConnectionEvent event)
{
    if (!parameter) {
        return;
    }
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)parameter;

    if (event == CS104_CON_EVENT_CONNECTION_OPENED) {
        CLogger::getInstance()->LOG_I("Iec104Comm Connection opened (%p)", con);
    }
    else if (event == CS104_CON_EVENT_CONNECTION_CLOSED) {
        CLogger::getInstance()->LOG_I("Iec104Comm Connection closed (%p)", con);
    }
    else if (event == CS104_CON_EVENT_ACTIVATED) {
        CLogger::getInstance()->LOG_I("Iec104Comm Connection activated (%p)", con);
        iec104Comm->c_connActived = true;
    }
    else if (event == CS104_CON_EVENT_DEACTIVATED) {
        CLogger::getInstance()->log_d("Connection deactivated (%p)", con);

        iec104Comm->c_connActived = false;
    }
}

void CIec104CommHandler::client_stop()
{
    CS104_Slave_stop(c_slave);

    CS104_Slave_destroy(c_slave);
}

void CIec104CommHandler::reverse_connEventHandler(void* parameter, CS104_Connection connection, CS104_ConnectionEvent event)
{
    if (!parameter) {
        return;
    }
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)parameter;

    //注册帧---------注册码GF_CZ_yingpeibei002
    uint8_t buf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };


    switch (event) {
    case CS104_CONNECTION_OPENED:
    {
        CLogger::getInstance()->LOG_I("Connection established.");
        iec104Comm->c_connActived = true;
        if (strlen(iec104Comm->c_register_code) > 0)
        {
            uint8_t *preg_code = new uint8_t[sizeof(buf) + strlen(iec104Comm->c_register_code) + 2];
            if (!preg_code){
                return;
            }
            preg_code[0] = 0x69;
            preg_code[1] = sizeof(buf) + strlen(iec104Comm->c_register_code);
            memcpy(preg_code + 2, buf, sizeof(buf));
            memcpy(preg_code + 2 + sizeof(buf), iec104Comm->c_register_code, strlen(iec104Comm->c_register_code));

            writeToSocket(connection, preg_code, sizeof(buf) + strlen(iec104Comm->c_register_code) + 2);
            delete[]preg_code;
        }
        else{
            CLogger::getInstance()->LOG_W("reverse_connEventHandler:master register coder is null.");
        }
    }
    break;
    case CS104_CONNECTION_CLOSED:
    {
        CLogger::getInstance()->LOG_I("Iec104 Connection closed. ");
        iec104Comm->c_connActived = false;

        pthread_t  rconn_thread_id;
        pthread_create(&rconn_thread_id, NULL, handle_reconnect_proc, iec104Comm);
    }
    break;
    case CS104_CONNECTION_FAILED:
    {
        CLogger::getInstance()->LOG_I("Iec104 Failed to connect.");
        pthread_t  rconn_thread_id;
        pthread_create(&rconn_thread_id, NULL, handle_reconnect_proc, iec104Comm);
    }
    break;
    case CS104_CONNECTION_STARTDT_CON_RECEIVED:
        CLogger::getInstance()->log_d("Received STARTDT_CON\n");
        break;
    case CS104_CONNECTION_STOPDT_CON_RECEIVED:
        CLogger::getInstance()->log_d("Received STOPDT_CON\n");
        break;
    default:
        CLogger::getInstance()->log_d("==========未知事件\n");
        break;
    }
}

bool CIec104CommHandler::reverse_recvAsduHandler(void* parameter, int address, CS101_ASDU asdu)
{
    CLogger::getInstance()->log_d("RECVD ASDU type: %s(%i) elements: %i\n",
        TypeID_toString(CS101_ASDU_getTypeID(asdu)),
        CS101_ASDU_getTypeID(asdu),
        CS101_ASDU_getNumberOfElements(asdu));

    if (!parameter) {
        return false;
    }
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)parameter;
    st_iec104_commptr* pst104Commptr = new st_iec104_commptr;
    if (!pst104Commptr){
        CLogger::getInstance()->LOG_E("asduHandler:new pointer error.");
        return false;
    }
    pst104Commptr->pcomm_ptr = iec104Comm;
    pst104Commptr->asdu = asdu;

    if (CS101_ASDU_getTypeID(asdu) == C_IC_NA_1)  //总召命令
    {
        pthread_t  interrog_thread_id;
        pthread_create(&interrog_thread_id, NULL, handle_interrogation_proc, pst104Commptr);
    }
    else if (CS101_ASDU_getTypeID(asdu) == C_SC_NA_1) { //单命令
        CLogger::getInstance()->log_d("received single command");

        pthread_t  remt_thread_id;
        pthread_create(&remt_thread_id, NULL, handle_remotecmd_proc, pst104Commptr);
    }
    else if (CS101_ASDU_getTypeID(asdu) == C_CI_NA_1){  //电能脉冲召唤命令
        CLogger::getInstance()->LOG_I("received remote pulse command.");
        pthread_t rp_thread_id;
        pthread_create(&rp_thread_id, NULL, handle_remotepulse_proc, pst104Commptr);
    }
    else{
        CLogger::getInstance()->log_d("received unsupported command");
        delete pst104Commptr;
    }

    return false;
}


void* CIec104CommHandler::comm_thread(void *arg)
{
    if (!arg){
        return nullptr;
    }
    pthread_detach(pthread_self());

    CIec104CommHandler *commHandler = (CIec104CommHandler *)arg;

    const char* ip = commHandler->c_master_addr.c_str();
    uint16_t port = (uint16_t)commHandler->c_master_port;  //IEC_60870_5_104_DEFAULT_PORT;

    glconn = CS104_Connection_create(ip, port);

    commHandler->c_alParams = CS104_Connection_getAppLayerParameters(glconn);
    commHandler->c_alParams->originatorAddress = 3;

    //心跳定时设为最大值，等于不发送
    CS104_APCIParameters   apciParams = CS104_Connection_getAPCIParameters(glconn);
    apciParams->t3 = 0xFFFF;


    CS104_Connection_setConnectionHandler(glconn, commHandler->reverse_connEventHandler, commHandler);
    CS104_Connection_setASDUReceivedHandler(glconn, commHandler->reverse_recvAsduHandler, commHandler);

    /* uncomment to log messages */
    CS104_Connection_setRawMessageHandler(glconn, commHandler->rawMessageHandler, commHandler);

    if (CS104_Connection_connect(glconn)){
        commHandler->c_connActived = true;
        CLogger::getInstance()->LOG_I("Connect to  IEC104 master station success!");
    }
    else{
        CLogger::getInstance()->LOG_I("Connect to IEC104 master station fail!");
    }

    while (glrun)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    return nullptr;
}

void*  CIec104CommHandler::monitor_thread(void *arg)
{ 
    if (!arg){
        return nullptr;
    }
    pthread_detach(pthread_self());

    CLogger::getInstance()->LOG_I("monitor_thread  started.");

    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)arg;
    uint64_t  t_interval = 0;
    while (glrun)
    {
        iec104Comm->c_curr_time = get_timestamp();
        if (iec104Comm->c_curr_time > iec104Comm->c_lastrecv_time)
        {
            t_interval = iec104Comm->c_curr_time - iec104Comm->c_lastrecv_time;
            t_interval /= 1000; //秒
            if (t_interval > g_no_recvdata_time)
            {
                CLogger::getInstance()->LOG_W("APP 重启，超过 %lld 秒未收到104主站数据.", t_interval);
                std::this_thread::sleep_for(std::chrono::milliseconds(4000));

                //延迟1s重启
                std::thread t1(exec_self, g_argv);
                t1.detach();
            }
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    }
    return nullptr;
}

void CIec104CommHandler::rawMessageHandler(void* parameter, uint8_t* msg, int msgSize, bool sent)
{
    CIec104CommHandler* commHandler = (CIec104CommHandler*)parameter;
    if (nullptr == commHandler) {
        CLogger::getInstance()->LOG_W("rawMessageHandler  paramter is null.");
        return;
    }

    if (sent)
        CLogger::getInstance()->log_d("Sended data to master station: ");
    else{
        CLogger::getInstance()->log_d("Recved data from master station: ");
        commHandler->c_lastrecv_time = get_timestamp();
    }

    int i;
    for (i = 0; i < msgSize; i++) {
        printf("%02x ", msg[i]);
    }

    printf("\n");
}

void* CIec104CommHandler::handle_reconnect_proc(void *arg)
{
    pthread_detach(pthread_self());
    if (!arg){
        return nullptr;
    }

    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)arg;

    std::this_thread::sleep_for(std::chrono::milliseconds(30000));   //休眠30秒再重连

    if (CS104_Connection_connect(glconn)){
        iec104Comm->c_connActived = true;
        CLogger::getInstance()->LOG_I("Reconnect iec104 master station success!");
    }
    else{
        CLogger::getInstance()->LOG_I("Reconnect iec104 master station fail!");
    }

    return nullptr;
}

void*  CIec104CommHandler::handle_interrogation_proc(void *arg)
{
    pthread_detach(pthread_self());
    if (!arg){
        return nullptr;
    }
    st_iec104_commptr* pI104CommPtr = (st_iec104_commptr*)arg;
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)pI104CommPtr->pcomm_ptr;

    CS101_ASDU  asdu = pI104CommPtr->asdu;

    //总召命令响应
    CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
    CS101_ASDU_setNegative(asdu, false);
    CS104_Connection_sendASDU(glconn, asdu);

    CLogger::getInstance()->LOG_I("interrogation ACT sended.");

    int ca = 0;
    ST_APDU_POINT_DATA stApduPonitData;
    ST_APDU_MEASUREDVAL_DATA stApduMearData;
    ST_APDU_INTERRTOTAL_DATA stApduIntertoalData;

    int ret = iec104Comm->c_iec104ServiceManager.get_dc_realtime_data(ca, stApduPonitData, stApduMearData, stApduIntertoalData);
    if (ret > 0)
    {
        //遥信
        if (stApduPonitData.lstObjs.size() > 0)
        {
            if ((stApduPonitData.ti == M_SP_NA_1) || (stApduPonitData.ti == M_SP_TB_1))
            {
                iec104Comm->create_send_singlePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduPonitData.lstObjs, nullptr, true);
            }
            else if ((stApduPonitData.ti == M_DP_TA_1) || (stApduPonitData.ti == M_DP_TB_1))
            {
                iec104Comm->create_send_doublePoint_Asdu(ca, stApduPonitData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduPonitData.lstObjs, nullptr, true);
            }
            else{
                CLogger::getInstance()->log_d("ti=%d not support.", stApduPonitData.ti);
            }
        }

        //遥测
        if (stApduMearData.lstObjs.size() > 0)
        {
            iec104Comm->create_send_MeasuredPoint_Asdu(ca, stApduMearData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduMearData.lstObjs, nullptr, true);
        }
        //遥脉
        if (stApduIntertoalData.lstObjs.size() > 0)
        {
            iec104Comm->create_send_CounterInterr_Asdu(ca, stApduIntertoalData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduIntertoalData.lstObjs, nullptr);

            for (auto itc = stApduIntertoalData.lstObjs.begin(); itc != stApduIntertoalData.lstObjs.end(); itc++)
            {
                ST_IEC104_INTERTOTAL_VAL  stInterTotal = *itc;
                delete stInterTotal.totalval;
            }
        }
        CLogger::getInstance()->log_d("interrogation rsp end.");
    }
    else{
        CLogger::getInstance()->LOG_I("get_dc_realtime_data-->datacenter query no data.");
    }

    delete pI104CommPtr;
    return nullptr;
}

void*  CIec104CommHandler::handle_remotepulse_proc(void *arg)
{
    pthread_detach(pthread_self());
    if (!arg){
        return nullptr;
    }
    st_iec104_commptr* pI104CommPtr = (st_iec104_commptr*)arg;
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)pI104CommPtr->pcomm_ptr;

    CS101_ASDU  asdu = pI104CommPtr->asdu;

    //电能脉冲命令响应
    CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);
    CS101_ASDU_setNegative(asdu, false);
    CS104_Connection_sendASDU(glconn, asdu);

    CLogger::getInstance()->log_d("Interrigation counter  ACT sended.");

    int ca = 0;
    ST_APDU_POINT_DATA stApduPonitData;
    ST_APDU_MEASUREDVAL_DATA stApduMearData;
    ST_APDU_INTERRTOTAL_DATA stApduIntertoalData;

    int ret = iec104Comm->c_iec104ServiceManager.get_dc_realtime_data(ca, stApduPonitData, stApduMearData, stApduIntertoalData);
    if (ret > 0)
    {
        bool bInfoAdded = true;
        CS101_ASDU newAsdu;

        //遥脉
        if (stApduIntertoalData.lstObjs.size() > 0)
        {
            iec104Comm->create_send_CounterInterr_Asdu(ca, stApduIntertoalData.ti, CS101_COT_INTERROGATED_BY_STATION, stApduIntertoalData.lstObjs, nullptr, true);

            for (auto itc = stApduIntertoalData.lstObjs.begin(); itc != stApduIntertoalData.lstObjs.end(); itc++)
            {
                ST_IEC104_INTERTOTAL_VAL  stInterTotal = *itc;
                delete stInterTotal.totalval;
            }
        }
    }
    delete pI104CommPtr;
    return nullptr;
}

void* CIec104CommHandler::handle_remotecmd_proc(void *arg)
{
    pthread_detach(pthread_self());
    if (!arg){
        return nullptr;
    }
    st_iec104_commptr* pI104CommPtr = (st_iec104_commptr*)arg;
    CIec104CommHandler* iec104Comm = (CIec104CommHandler*)pI104CommPtr->pcomm_ptr;

    CS101_ASDU  asdu = pI104CommPtr->asdu;
    if (CS101_ASDU_getCOT(asdu) == CS101_COT_ACTIVATION)   //激活
    {
        iec104Comm->remote_cmd_handler(asdu);
    }
    else
        CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_COT);

    CS104_Connection_sendASDU(glconn, asdu);

    delete pI104CommPtr;
    return nullptr;
}

void CIec104CommHandler::remote_cmd_handler(CS101_ASDU& asdu)
{
    InformationObject io = CS101_ASDU_getElement(asdu, 0);
    if (io) {
        //发送给南向
        int info_obj_addr = InformationObject_getObjectAddress(io);
        SingleCommand sc = (SingleCommand)io;
        bool bon = SingleCommand_getState(sc);

        CLogger::getInstance()->log_i("asduHandler:infobj_addr=%d,val=%d", info_obj_addr, bon);

        auto st104Cmd = CMappingRelationManager::getInstance()->get_dev_cmd_withobjaddr(info_obj_addr);
        if (st104Cmd->dev_id > 0)
        {
            CS101_ASDU_setCOT(asdu, CS101_COT_ACTIVATION_CON);

            TASK_PARAMS task_param;
            task_param.type = TASK_TYPE_SET_CMD_RULE;
            task_param.dev_id = st104Cmd->dev_id;
            task_param.task_id = 1;
            task_param.req_id = 1;
            ITEM_PARAMS  item_para;
            item_para.item_id = st104Cmd->cmd_id;
            item_para.type = 1;
            if (bon){
                item_para.value = "1";
            }
            else{
                item_para.value = "0";
            }
            task_param.items.push_back(item_para);

            c_tm->run_cmd(c_cm, c_mm, task_param);

            CLogger::getInstance()->log_d("asduHandler:down cmd send to runcmd queue.");

        }
        else{
            CS101_ASDU_setCOT(asdu, CS101_COT_UNKNOWN_IOA);
        }
        InformationObject_destroy(io);
    }
    else {
        CLogger::getInstance()->LOG_W("ERROR: message has no valid information object.");
    }
}

void CIec104CommHandler::create_send_CounterInterr_Asdu(int ca, int ti, int cot, std::list<ST_IEC104_INTERTOTAL_VAL> lstMearObjs, IMasterConnection connection, bool bInterr)
{
    //创建遥脉ASDU
    CS101_ASDU newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);

    int count = 0;
    auto ito = lstMearObjs.begin();
    while (ito != lstMearObjs.end())
    {
        ST_IEC104_INTERTOTAL_VAL stIntertotalVal = *ito;
        append_intertotalobj_toasdu(ti, newAsdu, stIntertotalVal);

        int payload_size = CS101_ASDU_getPayloadSize(newAsdu);
        if (payload_size >= MAX_PAYLOAD_SIZE)
        {
            if (glreverse104){
                CS104_Connection_sendASDU(glconn, newAsdu);
            }
            else{
                if (bInterr){
                    IMasterConnection_sendASDU(connection, newAsdu);
                }
                else{
                    CS104_Slave_enqueueASDU(c_slave, newAsdu);
                }
            }
            CS101_ASDU_destroy(newAsdu);
            CLogger::getInstance()->log_i("遥脉ASDU已发送,point num=%d", count);

            count = 0;
            ito++;
            newAsdu = CS101_ASDU_create(c_alParams, false, (CS101_CauseOfTransmission)cot, 0, ca, false, false);
            continue;
        }
        ito++;
        count++;
    }

    if (count > 0)
    {
        if (glreverse104){
            CS104_Connection_sendASDU(glconn, newAsdu);
        }
        else{
            if (bInterr){
                IMasterConnection_sendASDU(connection, newAsdu);
            }
            else{
                CS104_Slave_enqueueASDU(c_slave, newAsdu);
            }
        }
        CLogger::getInstance()->log_i("遥脉ASDU已发送,point num=%d", count);
    }
    CS101_ASDU_destroy(newAsdu);
    
}